package core

// Rule Interface
type BaseRule interface {
	Condition(ctx *Context) bool
	Action(ctx *Context)
	Execute(ctx *Context)
}

// Rule
type RuleStruct struct {
	condition func(ctx *Context) bool
	action    func(ctx *Context)
}

// Rule Constructor
func Rule(condition func(ctx *Context) bool, action func(ctx *Context)) *RuleStruct {
	ruleStruct := RuleStruct{
		condition: condition,
		action:    action,
	}
	return &ruleStruct
}

func(rule *RuleStruct) Condition(ctx *Context) bool{
	return rule.condition(ctx)
}

func(rule *RuleStruct) Action(ctx *Context){
	rule.action(ctx)
}

func(rule *RuleStruct) Execute(ctx *Context){
	if rule.Condition(ctx){
		rule.Action(ctx)
	}
}

func Traverse(rule BaseRule, f func(rule BaseRule) error, traverseType string){
	/*
	traverseType 遍历类型 dfs-深度优先 bfs-广度优先
	*/

	if traverseType == "dfs"{
		TraverseDFS(rule, f)
	}else if traverseType == "bfs"{
		TraverseBFS(rule, f)
	}else{
		TraverseDFS(rule, f)
	}

}

func TraverseDFS(r BaseRule, f func(rule BaseRule) error){
	err := f(r)
	if err != nil{
		panic(err)
	}
	if _, ok := interface{}(r).(*OrRuleStruct);ok{
		rules := r.(*OrRuleStruct).GetRules()
		for _, rule := range rules{
			TraverseDFS(rule, f)
		}
	}

	if _, ok := interface{}(r).(*AndRuleStruct);ok{
		rules := r.(*AndRuleStruct).GetRules()
		for _, rule := range rules{
			TraverseDFS(rule, f)
		}
	}

	if _, ok := interface{}(r).(*NotRuleStruct);ok{
		rule := r.(*NotRuleStruct).GetRule()
		TraverseDFS(rule, f)
	}
}

func TraverseBFS(r BaseRule, f func(rule BaseRule) error){
	_TraverseBFS(f, []BaseRule{r}...)
}

func _TraverseBFS(f func(rule BaseRule) error, rules...BaseRule){
	for _, r := range rules{
		err := f(r)
		if err != nil{
			panic(err)
		}
	}

	for _, r := range rules{
		if _, ok := interface{}(r).(*OrRuleStruct);ok{
			rules := r.(*OrRuleStruct).GetRules()
			_TraverseBFS(f, rules...)
		}else if _, ok := interface{}(r).(*AndRuleStruct);ok{
			rules := r.(*AndRuleStruct).GetRules()
			_TraverseBFS(f, rules...)
		}else if _, ok := interface{}(r).(*NotRuleStruct);ok{
			rule := r.(*NotRuleStruct).GetRule()
			_TraverseBFS(f, []BaseRule{rule}...)
		}else{}
	}
}